﻿Imports System.Threading

Friend Class ExclusiveLockStrategy
  Implements ILockStrategy

  Private _lock = New Object
  Private _lockedThread As Thread = Nothing
  Private _isDisposed As Boolean = False

  Public Function GetReadLock() As ISharedCollectionLock Implements ILockStrategy.GetReadLock
    Return GetLock()
  End Function

  Public Function GetWriteLock() As ISharedCollectionLock Implements ILockStrategy.GetWriteLock
    Return GetLock()
  End Function

  Private Function GetLock() As ISharedCollectionLock
    EnsureNotDisposed()
    If IsThreadLocked() Then
      Throw New LockRecursionException()
    End If

    Monitor.Enter(_lock)
    _lockedThread = Thread.CurrentThread
    Return New MonitorLock(Me)
  End Function

  Public ReadOnly Property ThreadCanRead As Boolean Implements ILockStrategy.ThreadCanRead
    Get
      EnsureNotDisposed()
      Return IsThreadLocked()
    End Get
  End Property

  Public ReadOnly Property ThreadCanWrite As Boolean Implements ILockStrategy.ThreadCanWrite
    Get
      EnsureNotDisposed()
      Return IsThreadLocked()
    End Get
  End Property

  Public ReadOnly Property SupportsConcurrentReads() As Boolean Implements ILockStrategy.SupportsConcurrentReads
    Get
      Return False
    End Get
  End Property

  Private Function IsThreadLocked() As Boolean
    Return Thread.CurrentThread.Equals(_lockedThread)
  End Function

  Public Sub [Exit]()
    EnsureNotDisposed()
    Monitor.Exit(_lock)
    _lockedThread = Nothing
  End Sub

  Private Sub EnsureNotDisposed()
    If _isDisposed Then
      Throw New ObjectDisposedException("ExclusiveLockStrategy")
    End If
  End Sub

  Public Sub Dispose() Implements IDisposable.Dispose
    _isDisposed = True 'todo remove disposable from interface?
  End Sub
End Class